from PIL import ImageFont, Image, ImageDraw
import numpy as np
from components import VolumeInfo
from components.VolumeInfo import ViewportTransform
from type import EnumViewType

font_draw = ImageFont.truetype('arial.ttf', size=14)
text_color = (0, 255, 0)
cross_ball_radius = 10
# bgr
r_color = (255, 0, 0)
g_color = (0, 255, 0)
b_color = (0, 0, 255)
endpoint_ball_radius = 5

one_line_height = 6


class InfoLayer:
    def __init__(self, view_type, dicom_tag_info, volume_info):
        self.view_type = view_type
        self.drawer = None
        self.draw_image = None
        self.dicom_tag_info = dicom_tag_info
        self.volume_info: VolumeInfo = volume_info
        self.scale_factor = 1
        self.size = (0, 0)  # h,w
        self.font_4_angle = ImageFont.truetype(r'C:/Windows/Fonts/simsun.ttc', size=16 * self.scale_factor)
        self.point_value = (0, 0, 0)
        self.direction_matrix = None
        self.init_direction_matrix()

    def init_direction_matrix(self):
        direction_matrix = np.array([])
        match self.view_type:
            case EnumViewType.Stack.value | EnumViewType.Ax.value:
                direction_matrix = np.array([
                    [0, 'A', 0],
                    ['R', 0, 'L'],
                    [0, 'P', 0],
                ])
            case EnumViewType.Sag.value:
                direction_matrix = np.array([
                    [0, 'S', 0],
                    ['A', 0, 'P'],
                    [0, 'I', 0],
                ])
            case EnumViewType.Cor.value:
                direction_matrix = np.array([
                    [0, 'S', 0],
                    ['R', 0, 'L'],
                    [0, 'I', 0],
                ])
        self.direction_matrix = direction_matrix

    def update_point_value(self, point_val):
        self.point_value = point_val

    def get_img_desc_info(self):
        manufacturer = self.dicom_tag_info.tags['manufacturer']
        ex = self.dicom_tag_info.tags['ex']
        se = self.dicom_tag_info.tags['se']
        current, total = self.volume_info.get_origin_current_total(self.view_type)
        current = current + 1
        wl, ww = self.volume_info.get_window_by_viewer_type(view_type=self.view_type)
        thickness = self.dicom_tag_info.tags['thickness']
        kV = self.dicom_tag_info.tags['kV']
        mA = self.dicom_tag_info.tags['mA']
        direction = self.get_direction()
        x, y, value = self.point_value
        upper_viewer_name = self.get_upper_viewer_name()
        key, position = self.get_position()
        ans = {
            "lt": [
                {
                    "": f'{manufacturer}',
                },
                {
                    "": f'{upper_viewer_name}',

                },
                {
                    "ex": f'{ex}',
                },
                {
                    "Se": f'{se}',
                },
                {
                    "Im": f'{current}/ {total}'
                }
            ],
            # 倒序
            "lb": [
                {
                    "W": ww,
                    'L': wl
                },
                {
                    "thickness": f'{thickness}',
                },
                {
                    "kV": f'{kV}',
                    "mA": f'{mA}',
                },
            ],
            "tm": [
                {
                    "": f'{direction["tm"]}',
                }
            ],
            "rm": [
                {
                    "": f'{direction["rm"]}',
                }
            ],
            "bm": [
                {
                    "": f'{direction["bm"]}',
                }
            ],
            "lm": [
                {
                    "": f'{direction["lm"]}',
                }
            ],
            # 倒序
            "rb": [
                {
                    "x": x,
                    "y": y,
                    "value": value
                },
            ]
        }
        if key is not None:
            ans["lt"][1].setdefault(key, position)
        return ans

    def get_position(self):
        if self.view_type == EnumViewType.Stack.value:
            return None, None
        physical_position = self.volume_info.slice_position.physical_position
        physical_position_dict = self.get_ILR_position(physical_position)
        match self.view_type:
            case 'ax':
                position = physical_position_dict['SI']
                return position[0], f'{position[1]}mm'
            case 'sag':
                position = physical_position_dict['LR']
                return position[0], f'{position[1]}mm'
            case 'cor':
                position = physical_position_dict['AP']
                return position[0], f'{position[1]}mm'

    def get_ILR_position(self, physical_point):
        L_R_mm = abs(physical_point[0])  # L/R距离
        A_P_mm = abs(physical_point[1])  # A/P距离
        S_I_mm = abs(physical_point[2])  # S/I距离

        # 判断方向
        direction = {
            'LR': 'L' if physical_point[0] > 0 else 'R',
            'AP': 'P' if physical_point[1] > 0 else 'A',
            'SI': 'I' if physical_point[2] > 0 else 'S'
        }

        return {
            'LR': (direction['LR'], L_R_mm),
            'AP': (direction['AP'], A_P_mm),
            'SI': (direction['SI'], S_I_mm)
        }

    def get_upper_viewer_name(self):
        match self.view_type:
            case 'stack':
                return 'Stack'
            case 'ax':
                return 'Axial'
            case 'sag':
                return 'Sagittal'
            case 'cor':
                return 'Coronal'

    def set_layer_size(self):
        png_size = self.volume_info.view_info[self.view_type].png_size
        self.size = (png_size[0] * self.scale_factor, png_size[1] * self.scale_factor)

    def init_layer(self):
        self.set_layer_size()
        height, width = self.size
        self.draw_image = Image.new('RGBA',
                                    (width, height), (0, 0, 0, 0))
        self.drawer = ImageDraw.Draw(self.draw_image)

    def get_info_layer(self):
        img_desc_info = self.get_img_desc_info()
        return img_desc_info

    def get_one_text_size(self):
        one_text = 'a'
        bbox = self.font_4_angle.getbbox(one_text)
        one_text_w = bbox[2] - bbox[0]  # 右 - 左 = 宽度
        one_text_h = bbox[3] - bbox[1]  # 下 - 上 = 高度
        return one_text_w, one_text_h

    def draw_text(self, drawer, content, posi, type='draw'):
        if content is None:
            return
        font = self.font_4_angle if type == '4angle' else font_draw
        drawer.text(posi, content, font=font, fill=text_color)

    def add_dicom_info(self, drawer, desc_info, w, h):
        padding = one_line_height * self.scale_factor
        one_text_w, one_text_h = self.get_one_text_size()

        rb_len = len(str(desc_info['rb'][0]['x'])) + len(str(desc_info['rb'][0]['y'])) + len(
            str(desc_info['rb'][0]['value'])) + 15
        position_dict = {
            # 左上角的起始位置
            "lt": (padding, padding),
            # 左下角的起始位置,倒着往上面写
            "lb": (padding, h - padding),
            # 右上角的截止位置
            "rt": (w - padding, padding),
            # 右下角的截止位置
            "rb": (w - padding - (rb_len * one_text_w), h - padding),
            "tm": (w // 2, padding),
            "rm": (w - padding - one_text_w, h // 2),
            "bm": (w // 2, h - padding - one_text_h),
            "lm": (padding, h // 2)
        }
        for position, desc_arr in desc_info.items():
            for index, item in enumerate(desc_arr):
                text = ''
                for each_line_k, each_line_v in item.items():
                    if each_line_k != '':
                        text = text + f"{each_line_k}: {each_line_v}" + ' '
                    else:
                        text = text + f"{each_line_v}" + ' '
                spacing_h = 6 * self.scale_factor
                every_line_offset = one_text_h + spacing_h
                posi = position_dict[position]
                if position == 'lt':
                    current_posi = (int(posi[0]), int(posi[1] + every_line_offset * index))
                elif position == 'lb':
                    current_posi = (int(posi[0]), int(posi[1] - every_line_offset * index - every_line_offset))
                elif position == 'rt':
                    current_posi = (int(posi[0] - one_text_w), int(posi[1] + every_line_offset * index))
                elif position == 'rb':
                    current_posi = (
                        int(posi[0] - one_text_w), int(posi[1] - every_line_offset * index - every_line_offset))
                else:
                    current_posi = (posi[0], posi[1])
                self.draw_text(drawer, text, current_posi, type='4angle')

    def rotate_direction(self, rotation):
        rotationK = rotation / 90
        self.direction_matrix = np.rot90(self.direction_matrix, int(rotationK))

    def hor_flip_direction(self):
        self.direction_matrix = np.flip(self.direction_matrix, axis=0)

    def ver_flip_direction(self):
        self.direction_matrix = np.flip(self.direction_matrix, axis=1)

    def get_direction(self):
        direction = {
            "tm": str(self.direction_matrix[0][1]),
            "rm": str(self.direction_matrix[1][2]),
            "bm": str(self.direction_matrix[2][1]),
            "lm": str(self.direction_matrix[1][0])
        }
        return direction
